/*
*********************************************************************************************************
*
*	模块名称 : BSP DMA
*
*********************************************************************************************************
*/

#ifndef _BSP_DMA_H_
#define _BSP_DMA_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include "stdint.h"
#include "stm32h5xx_ll_dma.h"

	/*******************************************************************************
	 * @brief  中断回调注册
	 *******************************************************************************/
	typedef struct
	{
		void (*stream10)(void);
		void (*stream11)(void);
		void (*stream12)(void);
		void (*stream13)(void);
		void (*stream14)(void);
		void (*stream15)(void);
		void (*stream16)(void);
		void (*stream17)(void);
		void (*stream20)(void);
		void (*stream21)(void);
		void (*stream22)(void);
		void (*stream23)(void);
		void (*stream24)(void);
		void (*stream25)(void);
		void (*stream26)(void);
		void (*stream27)(void);
	} dma_it_type;

	extern dma_it_type dma_it;

	/*******************************************************************************
	 * @brief  APP DMA type
	 *******************************************************************************/
	typedef struct
	{
		DMA_TypeDef *DMAx; // DMA 模块
		uint32_t stream;   // DMA 数据流
		uint32_t trig_src; // DMA 触发源
		IRQn_Type irqn;    // 中断号
	} app_dma_type;

#ifdef IN_DMA_MOUDLE
#define dma_stream_make(name, dmax, str, ch) \
	const app_dma_type name = {              \
		.DMAx = dmax,                        \
		.stream = str,                       \
		.trig_src = ch,                      \
		.irqn = dmax##_Stream##str##_IRQn	 \
	}
#else
#define dma_stream_make(name, dmax, str, ch) \
	extern const app_dma_type name
#endif

	/*******************************************************************************
	 * @brief  DMA CFG   name  moudle stream  tiggle src
	 *******************************************************************************/
	dma_stream_make(DMA_U01_RX, DMA2, 2, LL_DMA_CHANNEL_4);
	dma_stream_make(DMA_U01_TX, DMA2, 7, LL_DMA_CHANNEL_4);

	dma_stream_make(DMA_U04_RX, DMA1, 2, LL_DMA_CHANNEL_4);
	dma_stream_make(DMA_U04_TX, DMA1, 4, LL_DMA_CHANNEL_4);

	dma_stream_make(DMA_U06_RX, DMA2, 1, LL_DMA_CHANNEL_5);
	dma_stream_make(DMA_U06_TX, DMA2, 6, LL_DMA_CHANNEL_5);

	/*******************************************************************************
	 * @brief  APP DMA API
	 *******************************************************************************/
	void dma_nvic_set(const app_dma_type *dmax, uint32_t irq_en, void *callback);

	/*******************************************************************************
	 * @brief  配置
	 *******************************************************************************/
	typedef struct
	{
		uint8_t mem_to_periph;
		uint8_t cycle_mode;
		uint8_t mem_inc, periph_inc;
		uint16_t data_len;
		uint32_t prio;
		void *mem;
		volatile void *periph;
	} dma_stream_cfg_type;

	void dma_stream_config(const app_dma_type *dmax, dma_stream_cfg_type *cfg);

	/*******************************************************************************
	 * @brief  获取传输完成标志
	 * \param[in] dma, stream:[0-7]
	 * \retval:  0-No 1-Yes
	 *******************************************************************************/
	__STATIC_INLINE uint32_t dma_comp_flag_get(const app_dma_type *dmax)
	{
		uint32_t stream = dmax->stream;

		uint32_t bit_pos = ((stream % 4) / 2) * 16 + (stream % 2) * 6 + 5;

		// 2 WORD。 一个通道8bits， 每组第5bit指示完成。
		if ((&dmax->DMAx->MISR)[stream / 4] & (1UL << bit_pos))
			return 1;

		return 0;
	}

	/*******************************************************************************
	 * @brief  清除传输完成标志
	 * \param[in] dma, stream:[0-7]
	 * \retval:  0-No 1-Yes
	 *******************************************************************************/
	__STATIC_INLINE void dma_comp_flag_clr(const app_dma_type *dmax)
	{
		uint32_t stream = dmax->stream;

		uint32_t bit_pos = ((stream % 4) / 2) * 16 + (stream % 2) * 6;

		// 2 WORD。 一个通道6bits， 清除所有标志。
		(&dmax->DMAx->SECCFGR)[stream / 4] = 0x3DUL << bit_pos;
	}

/*******************************************************************************
 * @brief  库接口映射
 * \param[in] dma, stream:[0-7]
 * \retval:  0-No 1-Yes
 *******************************************************************************/
	/* 数据流反初始化 */
#define dma_stream_deinit(dmax) LL_DMA_DeInit((dmax)->DMAx, (dmax)->stream)
	
	/* 数据流是否已开启 */
#define is_dma_stream_enable(dmax) LL_DMA_IsEnabledStream((dmax)->DMAx, (dmax)->stream)
	
	/* 使能数据流 */
#define dma_stream_enable(dmax) \
	dma_comp_flag_clr(dmax);    \
	LL_DMA_EnableStream((dmax)->DMAx, (dmax)->stream)
	
	/* 禁能数据流 */
#define dma_stream_disable(dmax) LL_DMA_DisableStream((dmax)->DMAx, (dmax)->stream)
	
	/* 设置内存地址 */
#define dma_stream_set_mem_addr(dmax, addr) LL_DMA_SetMemoryAddress((dmax)->DMAx, (dmax)->stream, (addr))

	/* 设置外设数据地址 */
#define dma_stream_set_periph_addr(dmax, addr) LL_DMA_SetPeriphAddress((dmax)->DMAx, (dmax)->stream, (addr))

	/* 设置数据长度 */
#define dma_stream_set_data_len(dmax, len) LL_DMA_SetDataLength((dmax)->DMAx, (dmax)->stream, (len))

	/* 获取当前DMA数据长度指针 */
#define dma_stream_get_data_len(dmax) LL_DMA_GetDataLength((dmax)->DMAx, (dmax)->stream)

	/* 完成中断使能 */
#define dma_stream_complete_isr_enable(dmax) LL_DMA_EnableIT_TC((dmax)->DMAx, (dmax)->stream)

#ifdef __cplusplus
}
#endif

#endif
